package org.dcm4che3.tool.printscp;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.ListIterator;
import java.util.Random;
import java.util.UUID;

import org.dcm4che3.data.Attributes;
import org.dcm4che3.data.Sequence;
import org.dcm4che3.data.Tag;
import org.dcm4che3.data.UID;
import org.dcm4che3.data.VR;
import org.dcm4che3.data.Value;
import org.dcm4che3.io.DicomOutputStream;
import org.dcm4che3.net.Association;
import org.dcm4che3.net.Commands;
import org.dcm4che3.net.Dimse;
import org.dcm4che3.net.Status;
import org.dcm4che3.net.pdu.PresentationContext;
import org.dcm4che3.net.service.AbstractDicomService;
import org.dcm4che3.tool.print.entity.Config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.druid.util.StringUtils;
import com.alibaba.fastjson.JSONObject;

public class ImageBoxService extends AbstractDicomService {

	private final static Logger log = LoggerFactory.getLogger(ImageBoxService.class);
	
	private Config config = null;
	private SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
	private SimpleDateFormat sdfTime = new SimpleDateFormat("HHmmss");
	JSONObject remoteInfo = null;
	public ImageBoxService(Config config, JSONObject remoteInfo, String ... sopClass) {
		super(sopClass);
		this.config = config;
		this.remoteInfo = remoteInfo;
	}
	
	@Override
	protected void onDimseRQ(Association as, PresentationContext pc, Dimse dimse, Attributes cmd, Attributes data)
			throws IOException {
		Attributes rsp = Commands.mkNSetRSP(cmd, Status.Success);
        as.tryWriteDimseRSP(pc, rsp, null);
		try {
			store(as, pc, cmd, data);
		} catch (Exception e) {
			log.error("fail to process store" ,e);
		}
	}
	
	protected void store(Association as, PresentationContext pc,
            Attributes rq, Attributes rqAttrs) throws IOException {
	   boolean isColor = false;
	   
	   String remoteIp = as.getSocket().getInetAddress().getHostAddress();
	   String remoteAe = as.getCallingAET();
	   
	   String requestSOPInstanceUid = rq.getString(Tag.RequestedSOPInstanceUID);
	   JSONObject filmBoxAttr = FilmBoxService.getFilmbox(requestSOPInstanceUid);
	   
	   if (filmBoxAttr == null) {
		   filmBoxAttr = FilmBoxService.getFilmboxAE(remoteIp + remoteAe);
	   }
	   
	   String filmBox = null, imageDisplayFormat = "STANDARD\\1,1", fileSize = "", filmOrientation = "";
	   String imageBoxPosition = "1";
	   if (filmBoxAttr == null) {
		   log.error("this should not happen, fail to find filmbox info={}", rq);
		   filmBox = sdf.format(new Date()) + File.separator + UUID.randomUUID().toString().replace("-","");
		   rq.setString(Tag.RequestedSOPInstanceUID, VR.UI, getRandomInstanceSopUid());
	   } else {
		   filmBox = filmBoxAttr.getString("filmBoxName");
		   imageDisplayFormat = filmBoxAttr.getString("imageDisplayFormat");
		   fileSize = filmBoxAttr.getString("filmSize");
		   filmOrientation = filmBoxAttr.getString("filmOrientation");
		   imageBoxPosition = filmBoxAttr.getString("imageBoxPosition");
	   }
//	   String storeFile = config.getDicomStoreDir() + File.separator + filmBox +  File.separator + 
//			   (rq.contains(Tag.ImagePosition) ? rq.getString(Tag.ImageBoxPosition) : imageBoxPosition) + ".dcm";
	   
	   String storeFile = config.getDicomStoreDir() + File.separator + filmBox +  File.separator + UUID.randomUUID() + ".dcm";
//			   (rq.contains(Tag.ImagePosition) ? rq.getString(Tag.ImageBoxPosition) : imageBoxPosition) + ".dcm";
	   
	   File parent = new File(storeFile).getParentFile();
	   if (!parent.exists()) {
		   parent.mkdirs();
	   }
	   
	   DicomOutputStream out = null;
	   log.info("store Fil=====================" + storeFile + ", req={}", rq);
	   
	   try {
		   String sopInstanceUid = imitateSopInstanceUid();
		   out = new DicomOutputStream(new File(storeFile));
		   Attributes dataSet = new Attributes();
//		   dataSet.setString(Tag.aeti, null, sopInstanceUid)
		 //和打印有关系的数据
		   dataSet.setInt(Tag.ImageBoxPosition, VR.US, rqAttrs.getInts(Tag.ImageBoxPosition));
		   Sequence seqData = rqAttrs.getSequence(Tag.BasicGrayscaleImageSequence);
		   if (seqData == null) {
			   seqData = rqAttrs.getSequence(Tag.BasicColorImageSequence);
			   if (seqData != null) {
				   isColor = true;
			   }
		   }
		   if (seqData != null) {
			   ListIterator<Attributes> list = seqData.listIterator();
			   while (list.hasNext()) {
				   dataSet.addAll(list.next());
			   }
		   } else {
			   dataSet.addAll(rqAttrs);
			   log.error("fail to sequence tag info from file={}, rqData={}", storeFile, rq);
		   }
		  
		   dataSet.setString(Tag.SpecificCharacterSet, VR.CS, "ISO_IR 100");
		   dataSet.setBytes(Tag.StudyInstanceUID, VR.UI, imitateStudyInstanceUid().getBytes());
		   dataSet.setBytes(Tag.SeriesInstanceUID, VR.UI, imitateSeriesUid().getBytes());
		   dataSet.setBytes(Tag.SOPClassUID, VR.UI, UID.HardcopyGrayscaleImageStorageSOPClassRetired.getBytes());
		   dataSet.setBytes(Tag.SOPInstanceUID,VR.UI, sopInstanceUid.getBytes());
		   dataSet.setBytes(Tag.PatientName, VR.PN, "*".getBytes());
		   dataSet.setBytes(Tag.Modality, VR.CS, "FT".getBytes());
		   //自定义字段，第四位必须是1.
		   dataSet.setString(Integer.parseInt("00910000", 16), VR.LO, sdf.format(new Date()));
		   dataSet.setString(Integer.parseInt("00910011", 16), VR.LO, sdfTime.format(new Date()));
		   dataSet.setString(Integer.parseInt("00910012", 16), VR.LO, as.getCallingAET());
		   dataSet.setString(Integer.parseInt("00910013", 16), VR.LO, as.getSocket().getInetAddress().getHostAddress());	
		   
		   dataSet.setString(Tag.PrintPriority, VR.CS, "HIGH");
		   dataSet.setString(Tag.MediumType, VR.CS, "BLUE");
		   dataSet.setString(Tag.FilmDestination, VR.CS, "MAGAZINE");
		   dataSet.setString(Tag.ImageDisplayFormat, VR.ST, imageDisplayFormat);
		   
		   if (!isEmpty(fileSize)) {
			   dataSet.setString(Tag.FilmSizeID, VR.CS, fileSize);
		   }
		   if (!isEmpty(filmOrientation)) {
			   dataSet.setString(Tag.FilmOrientation, VR.CS, filmOrientation);
		   } else {
			   dataSet.setString(Tag.FilmOrientation, VR.CS, "PORTRAIT");
		   }
//		   dataSet.setString(Tag.ImageBoxPosition, VR.US, "1");
		   
		   Attributes fileMeta = dataSet.createFileMetaInformation(pc.getTransferSyntax());
		   fileMeta.setBytes(Tag.ImplementationVersionName, VR.SH, "DCM-FT".getBytes());
		   out.writeDataset(fileMeta, dataSet);
		   FilmBoxService.removeImgIdxFromFilmBox(requestSOPInstanceUid);
		   log.info("do transfer===={}", config.isDoTransfer());
		   if (config.isDoTransfer()) {
			   try {
				   doTransfer(storeFile, remoteInfo);
			   } catch (Exception e) {
				   log.error("Fail to do remote data transer. remote={}, filePath={}", remoteInfo, storeFile);
			   }
		   }
		   
	   } catch (Exception e) {
		   log.error("fail to store dcm file", e);
	   } finally {
		   try {
			   if (out != null) {
				   out.close();
			   }
		   } catch (Exception e) {}
	   }
	}
	
	private String imitateStudyInstanceUid() {
		Random r = new Random();
		SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS");
		String randStr = String.valueOf(r.nextDouble()).substring(2,8);
		String uid = "1.2.840.213620.186.90861654864." + sdf.format(new Date()) + "." + randStr;
		return uid;
	}
	
	private String imitateSeriesUid() {
		Random r = new Random();
		SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS");
		String randStr = String.valueOf(r.nextDouble()).substring(2,8);
		String uid = "1.2.841.2516852." + sdf.format(new Date()) + "." + randStr;
		return uid;
	}
	
	private String imitateSopInstanceUid() {
		Random r = new Random();
		SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS");
		String randStr = String.valueOf(r.nextDouble()).substring(2,8);
		String uid = "1.2.40.0.13.0.10.185.113.66." + sdf.format(new Date()) + "." + randStr;
		return uid;
	}
	
	private void doTransfer(String filePath, JSONObject remoteInfo) throws Exception {
		String cmd = config.getTransferExePath() + " " + filePath + " " + remoteInfo.getString("ae") + " " + remoteInfo.getString("ip") + " " + remoteInfo.getString("port");
		log.info("transfer command = {}", cmd);
		long start = System.currentTimeMillis();
		Process p = Runtime.getRuntime().exec(cmd);
//        BufferedReader br = null;
        try {
//            br = new BufferedReader(new InputStreamReader(p.getInputStream()));
//            String readLine = br.readLine();
//            StringBuilder builder = new StringBuilder();
//            while (readLine != null) {
//                readLine = br.readLine();
//                builder.append(readLine);
//            }
            p.waitFor();
            if (p.exitValue() == -1) {
            	log.error("transfer command = {}", cmd);
            }
            log.info("transfer={} rst={} cost={} ms", filePath, p.exitValue(), (System.currentTimeMillis() - start));
        } finally {
//            if (br != null) {
//                br.close();
//            }
        }
	}
	
	private boolean isEmpty(String str) {
		return (str == null || "".equals(str));
	}
	
	private String getRandomInstanceSopUid() {
		Random r = new Random();
		SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS");
		String randStr = String.valueOf(r.nextDouble()).substring(2,8);
		String uid = "1.2.689." + sdf.format(new Date()) + "." + randStr;
		return uid;
	}
}
